﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using Medianamik.Core.Synchronization;
using DALS = Medianamik.Core.DAL.SubSonicDAL;

namespace Medianamik.Core.DAL.Repositories
{
    public class NodeTypeRepository : INodeTypeRepository
    {
        public IEnumerable<NodeType> All(bool includeManyToMany)
        {
            var dalTypes = new DALS.TypeCollection();
            
            if (!includeManyToMany)
            {
                dalTypes.Where(DALS.Type.Columns.IsManyToMany, false);
            }

            dalTypes.OrderByAsc(DALS.Type.Columns.Name);

            dalTypes.Load();

            foreach (var dalType in dalTypes)
            {
                yield return AdaptFrom(dalType);
            }
        }

        public NodeType GetById(Guid id)
        {
            return NodeTypeManager.GetNodeType(id);
        }

        private NodeType AdaptFrom(DALS.Type dalType)
        {
            var type = new NodeType(dalType.TypeId, dalType.Name, dalType.CanHaveChilds,
                dalType.IsGenerated, dalType.IsAbstract, dalType.IsSystem, dalType.IsManyToMany, dalType.Path, dalType.Depth,
                dalType.ParentTypeId)
            {
                Flags = new BitVector32(dalType.Flags),
                Description = dalType.Description,
                IsVersioned = dalType.IsVersioned,
                IsDeleted = dalType.IsDeleted,
                IsAdmin = dalType.IsAdmin
            };

            if (!string.IsNullOrEmpty(dalType.ExtendedProperties))
            {
                type.ExtendedProperties = 
                    new NodeTypeExtendedProperties(dalType.ExtendedProperties);
            }

            type.Status = EntityStates.Loaded;

            return type;
        }

        public IList<NodeType> ChildsOf(Guid typeId, bool inclusive, int maxDepth,
            bool inlcudeAbstractTypes)
        {
            var nodeTypes = NodeTypeManager.GetAllTypes(false)
                 .Where(t => t.Path.Contains(typeId.ToString(),
                     StringComparison.OrdinalIgnoreCase)).ToList();

            var currentNodeType = nodeTypes.First(t => t.ID.Equals(typeId));

            if (!inclusive)
            {
                nodeTypes.Remove(currentNodeType);
            }

            if (maxDepth > 0)
            {
                nodeTypes.RemoveAll(t => t.Depth > (currentNodeType.Depth + maxDepth));
            }

            if (!inlcudeAbstractTypes)
            {
                nodeTypes.RemoveAll(t => t.IsAbstract);
            }

            return nodeTypes;
        }

        public IEnumerable<NodeType> TypesImplementing(Guid interfaceId)
        {
            return NodeTypeManager.GetNodeTypes(interfaceId).Select(imp => imp.Owner);
        }

        public bool TypeIsImplementing(Guid typeId, Guid interfaceId)
        {
            return NodeTypeManager.GetNodeType(typeId)
                .Interfaces.Any(i => i.InterfaceId.Equals(interfaceId));
        }

        public bool NodesOfTypeCanHaveChildren(Guid typeId)
        {
            return NodeManager.NodeCanHaveChildren(typeId);
        }
    }
}
